package com.hzy.oms.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.hzy.constant.Constants;
import com.hzy.enums.OrderStatus;
import com.hzy.oms.domain.OrderInfo;
import com.hzy.oms.domain.OrderItem;
import com.hzy.oms.domain.OrderOperateHistory;
import com.hzy.oms.domain.WechatPaymentHistory;
import com.hzy.oms.domain.vo.PayNotifyMessageVo;
import com.hzy.oms.mapper.OrderInfoMapper;
import com.hzy.oms.mapper.OrderItemMapper;
import com.hzy.oms.mapper.OrderOperateHistoryMapper;
import com.hzy.oms.mapper.WechatPaymentHistoryMapper;
import com.hzy.oms.request.OrderPayRequest;
import com.hzy.oms.response.OrderPayResponse;
import com.hzy.oms.service.OrderPayService;
import com.hzy.ums.domain.MemberWechat;
import com.hzy.ums.mapper.MemberWechatMapper;
import com.hzy.utils.RedisExUtils;
import com.hzy.wechat.WechatPayConfig;
import com.hzy.wechat.WechatPayData;
import com.hzy.wechat.WechatPayService;
import com.hzy.wechat.WechatPayUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Copyright (C), 2022-2023
 * FileName: OrdePayService
 * Description: 订单支付相关接口
 * Author:   zengxin
 * Date:     2023/10/21 16:05
 */
@Slf4j
@RequiredArgsConstructor
//@Service(value = "weChatOrderPayService")
@Service
public class WeChatOrderPayServiceImpl implements OrderPayService {

    private final OrderInfoMapper orderMapper;

    private final MemberWechatMapper memberWechatMapper;

    private final OrderItemMapper orderItemMapper;

    private final WechatPaymentHistoryMapper wechatPaymentHistoryMapper;

//    private final WechatPayService wechatPayService;

    private final OrderOperateHistoryMapper orderOperateHistoryMapper;

    private final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");

    @Override
    @Transactional
    public OrderPayResponse orderPay(OrderPayRequest request) {
        QueryWrapper<OrderInfo> qw = new QueryWrapper<>();
        qw.eq("pay_id", request.getPayId());
        qw.eq("status", 0);
        List<OrderInfo> orderList = orderMapper.selectList(qw);
        if (CollectionUtil.isEmpty(orderList)){
            throw new RuntimeException("没有待支付的订单");
        }
        QueryWrapper<MemberWechat> memberWechatQw = new QueryWrapper<>();
        memberWechatQw.eq("member_id", request.getMemberId());
        MemberWechat memberWechat = memberWechatMapper.selectOne(memberWechatQw);
        if (memberWechat == null || StrUtil.isBlank(memberWechat.getOpenid())){
            throw new RuntimeException("获取用户openId失败");
        }
        QueryWrapper<OrderItem> orderItemQw = new QueryWrapper<>();
        orderItemQw.eq("order_id", orderList.get(0).getId());
        List<OrderItem> orderItemList = orderItemMapper.selectList(orderItemQw);
        String orderDesc = orderItemList.get(0).getProductName().substring(0, Math.min(40, orderItemList.get(0).getProductName().length()));
        //保存微信支付历史
        Date optDate = new Date();
        QueryWrapper<WechatPaymentHistory> wxPaymentQw = new QueryWrapper<>();
        wxPaymentQw.eq("order_id", orderList.get(0).getPayId());
        wxPaymentQw.eq("op_type", Constants.PaymentOpType.PAY);
        WechatPaymentHistory wechatPaymentHistory = wechatPaymentHistoryMapper.selectOne(wxPaymentQw);
        if (wechatPaymentHistory == null){
            wechatPaymentHistory = new WechatPaymentHistory();
            wechatPaymentHistory.setOrderId(orderList.get(0).getPayId());
            wechatPaymentHistory.setMemberId(request.getMemberId());
            wechatPaymentHistory.setOpenid(memberWechat.getOpenid());
            wechatPaymentHistory.setTitle(orderItemList.get(0).getProductName());
            wechatPaymentHistory.setMoney(orderList.get(0).getPayAmount());
            wechatPaymentHistory.setOpType(Constants.PaymentOpType.PAY);
            wechatPaymentHistory.setPaymentStatus(0);
            wechatPaymentHistory.setCreateBy(request.getMemberId().toString());
            wechatPaymentHistory.setCreateTime(optDate);
            wechatPaymentHistory.setUpdateBy(request.getMemberId().toString());
            wechatPaymentHistory.setUpdateTime(optDate);
            wechatPaymentHistoryMapper.insert(wechatPaymentHistory);
        }else {
            wechatPaymentHistory.setMoney(orderList.get(0).getPayAmount());
            wechatPaymentHistoryMapper.updateById(wechatPaymentHistory);
        }
        //请开启微信支付 wechat.enabled=true
        //调用wx的jsapi拿prepayId，返回签名等信息
        String openId = memberWechat.getOpenid();
        String appId = WechatPayData.appId;
        if (request.getWechatType().equals("jsapi")) {
            openId = memberWechat.getRoutineOpenid();
            appId = WechatPayData.miniProgramAppId;
        }
//        String prepayId = wechatPayService.jsapiPay(
//                String.valueOf(request.getPayId()),
//                orderDesc,
//                Integer.valueOf(orderList.stream().map(OrderInfo::getPayAmount).
//                        reduce(BigDecimal.ZERO, BigDecimal::add).multiply(new BigDecimal(100)).stripTrailingZeros().toPlainString()),
//                openId,
//                request.getMemberId(),
//                appId
//        );
        String prepayId = null;
        OrderPayResponse response = new OrderPayResponse();
        response.setPayType(2);
        String nonceStr = WechatPayUtil.generateNonceStr();
        long timeStamp = WechatPayUtil.getCurrentTimestamp();
        prepayId = "prepay_id=" + prepayId;
        String signType = "RSA";
        String paySign = null;
        String signatureStr = Stream.of(appId, String.valueOf(timeStamp), nonceStr, prepayId)
                .collect(Collectors.joining("\n", "", "\n"));
        try {
            paySign = WechatPayUtil.getSign(signatureStr, WechatPayData.privateKeyPath);
        } catch (Exception e) {
            throw new RuntimeException("支付失败");
        }
        response.setAppId(appId);
        response.setTimeStamp(String.valueOf(timeStamp));
        response.setNonceStr(nonceStr);
        response.setSignType(signType);
        response.setPackage_(prepayId);
        response.setPaySign(paySign);
        return response;
    }

    @Override
    @Transactional
    public void payNotify(HttpServletRequest request) {
        try{
            log.info("收到了微信支付回调");
            // 从请求头中获取信息
            String timestamp  = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String signature = request.getHeader("Wechatpay-Signature");
            String singType = request.getHeader("Wechatpay-Signature-Type");
            String wechatPayCertificateSerialNumber = request.getHeader("Wechatpay-Serial");
            // 拿到请求体body
            StringBuilder requestBody = new StringBuilder();
            String line;
            BufferedReader reader;
            reader = request.getReader();
            while (null != (line = reader.readLine())) {
                requestBody.append(line);
            }
            // 构造 RequestParam
            RequestParam requestParam = new RequestParam.Builder()
                    .serialNumber(wechatPayCertificateSerialNumber)
                    .nonce(nonce)
                    .signature(signature)
                    .timestamp(timestamp)
                    .body(requestBody.toString())
                    .build();
            log.info("【requestParam】" + JSONObject.toJSONString(requestParam));
            //初始化了 RSAAutoCertificateConfig
            Config config = WechatPayConfig.getInstance();
            // 初始化解析器 NotificationParser
            NotificationParser parser = new NotificationParser((NotificationConfig) config);
            // 以支付通知回调为例，验签、解密并转换成 Transaction
            Transaction transaction = parser.parse(requestParam, Transaction.class);
            log.info("【transaction】" + JSONObject.toJSONString(transaction));
            PayNotifyMessageVo message = new PayNotifyMessageVo();
            message.setOutTradeNo(Long.valueOf(transaction.getOutTradeNo()));
            message.setMemberId(Long.valueOf(transaction.getAttach()));
            message.setTradeStatus(transaction.getTradeState());
            if (StrUtil.isEmpty(transaction.getSuccessTime())){
                throw new RuntimeException("微信支付回调失败");
            }
            message.setPayTime(formatter.parse(transaction.getSuccessTime().substring(0, transaction.getSuccessTime().indexOf("+"))));
            message.setTradeNo(transaction.getTransactionId());
            log.info("【订单支付回调】" + JSONObject.toJSONString(message));
            Date optDate = new Date();
            String redisKey = "oms_order_pay_notify_" + message.getOutTradeNo();
            String redisValue = message.getOutTradeNo() + "_" + System.currentTimeMillis();
            RedisExUtils.lock(redisKey, redisValue, 60);
            //先判断回信回调的是否未success
            if (!Transaction.TradeStateEnum.SUCCESS.equals(message.getTradeStatus())){
                log.error("【订单支付回调】订单状态不是支付成功状态" + message.getTradeStatus());
                throw new RuntimeException();
            }
            QueryWrapper<WechatPaymentHistory> paymentWrapper = new QueryWrapper<>();
            paymentWrapper.eq("order_id", message.getOutTradeNo());
            paymentWrapper.eq("op_type", Constants.PaymentOpType.PAY);
            WechatPaymentHistory paymentHistory = wechatPaymentHistoryMapper.selectOne(paymentWrapper);
            if (paymentHistory.getPaymentStatus() != Constants.PaymentStatus.INCOMPLETE) {
                log.info("【订单支付回调】支付订单不是未支付状态，不再处理" + "orderId" + paymentHistory.getOrderId() + "status" + paymentHistory.getPaymentStatus());
                throw new RuntimeException();
            }
            QueryWrapper<OrderInfo> orderQw = new QueryWrapper<>();
            orderQw.eq("pay_id", message.getOutTradeNo());
            orderQw.eq("status", OrderStatus.UN_PAY.getType());
            List<OrderInfo> orderList = orderMapper.selectList(orderQw);
            orderList.forEach(order -> {
                order.setPaymentTime(optDate);
                order.setStatus(OrderStatus.NOT_DELIVERED.getType());
                orderMapper.updateById(order);

                OrderOperateHistory optHistory = new OrderOperateHistory();
                optHistory.setOrderId(order.getId());
                optHistory.setOrderSn(order.getOrderSn());
                optHistory.setOperateMan("" + order.getMemberId());
                optHistory.setOrderStatus(OrderStatus.NOT_DELIVERED.getType());
                optHistory.setCreateTime(optDate);
                optHistory.setCreateBy(order.getMemberId().toString());
                optHistory.setUpdateBy(order.getMemberId().toString());
                optHistory.setUpdateTime(optDate);
                orderOperateHistoryMapper.insert(optHistory);
            });
            UpdateWrapper<WechatPaymentHistory> paymentHistoryUpdateWrapper = new UpdateWrapper<>();
            paymentHistoryUpdateWrapper.eq("order_id", message.getOutTradeNo()).set("payment_id", message.getTradeNo())
                    .set("payment_status", Constants.PaymentStatus.COMPLETE).set("update_time", optDate);
            wechatPaymentHistoryMapper.update(null, paymentHistoryUpdateWrapper);
            RedisExUtils.unLock(redisKey, redisValue);
        }catch (Exception e){
            log.error("订单支付回调异常",e);
            throw new RuntimeException("订单支付回调异常");
        }
//        return ResponseEntity.ok("订单支付回调成功");
    }
}
